package com.ccteam.fluidmusic.view.adapters.databinding;

import android.view.ViewGroup;

import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.databinding.OnRebindCallback;
import androidx.databinding.ViewDataBinding;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListAdapter;
import androidx.recyclerview.widget.RecyclerView;

import com.ccteam.fluidmusic.view.adapters.databinding.DataBindViewHolder;

import org.jetbrains.annotations.NotNull;

import java.util.List;

/**
 *
 * @author Xiaoc
 * @date 2020.10.22
 *
 * DataBinding版基于ListAdapter的RecycleView适配器
 *
 * {@link ListAdapter}可以在数据更新时，按照自定义的比对数据进行按需更新（局部更新），并且支持更新动画
 * 需要实现{@link DiffUtil}中的比对接口
 *
 * 同时此适配器基于DataBinding绑定数据，通过DataBinding能够快速进行RecyclerView的适配器编写，避免繁琐且低效率的findId操作
 *
 * 数据基于{@link DataBindViewHolder}，通过ViewHolder存储binding，以便从holder中得到对应控件
 * 当Data数据发生变化时，避免整体刷新数据
 * @param <T> 基于ViewDataBinding的类，也就是生成的DataBinding类型
 */
public abstract class BaseDataBindAdapter<T extends ViewDataBinding,E>
        extends ListAdapter<E, DataBindViewHolder<T>> {
    private static final Object DB_PAYLOAD = new Object();

    @Nullable
    private RecyclerView mRecyclerView;

    private final OnRebindCallback<T> mOnRebindCallback = new OnRebindCallback<T>() {
        @Override
        public boolean onPreBind(T binding) {
            if(mRecyclerView == null || mRecyclerView.isComputingLayout()){
                return true;
            }
            int childAdapterPosition = mRecyclerView.getChildAdapterPosition(binding.getRoot());
            if(childAdapterPosition == RecyclerView.NO_POSITION){
                return true;
            }
            notifyItemChanged(childAdapterPosition,DB_PAYLOAD);
            return false;
        }
    };

    /**
     * 传入比对回调接口
     */
    public BaseDataBindAdapter(@NonNull DiffUtil.ItemCallback<E> diffCallback) {
        super(diffCallback);
    }

    @NonNull
    @Override
    public DataBindViewHolder<T> onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        DataBindViewHolder<T> vh = DataBindViewHolder.create(parent, viewType);
        vh.binding.addOnRebindCallback(mOnRebindCallback);
        return vh;
    }

    @Override
    public void onBindViewHolder(@NonNull DataBindViewHolder<T> holder, int position, @NonNull List<Object> payloads) {
        // when a VH is rebound to the same item, we don't have to call the setters
        if (payloads.isEmpty() || hasNonDataBindingInvalidate(payloads)) {
            bindItem(holder, position, payloads);
        }
        holder.binding.executePendingBindings();
    }

    /**
     * 绑定数据和监听事件
     * @param holder ViewHolder视图数据保持层
     * @param position 位置
     * @param payloads
     */
    protected abstract void bindItem(DataBindViewHolder<T> holder, int position,
                                     List<Object> payloads);

    private boolean hasNonDataBindingInvalidate(List<Object> payloads) {
        for (Object payload : payloads) {
            if (payload != DB_PAYLOAD) {
                return true;
            }
        }
        return false;
    }

    @Override
    public final void onBindViewHolder(@NotNull DataBindViewHolder<T> holder, int position) {
        throw new IllegalArgumentException("just overridden to make final.");
    }

    @Override
    public void onAttachedToRecyclerView(@NotNull RecyclerView recyclerView) {
        mRecyclerView = recyclerView;
    }

    @Override
    public void onDetachedFromRecyclerView(@NotNull RecyclerView recyclerView) {
        mRecyclerView = null;
    }

    @Override
    public final int getItemViewType(int position) {
        return getItemLayoutId(position);
    }

    /**
     * 获得当前position的布局ID
     * @param position 当前位置
     * @return 布局ID
     */
    @LayoutRes
    abstract public int getItemLayoutId(int position);

}
